//===--- UnsafeBufferPointer.swift.gyb ------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// An iterator for the elements in the buffer referenced by
/// `UnsafeBufferPointer` or `UnsafeMutableBufferPointer`.
public struct UnsafeBufferPointerIterator<Element>
  : IteratorProtocol, Sequence {

  /// Advances to the next element and returns it, or `nil` if no next element
  /// exists.
  ///
  /// Once `nil` has been returned, all subsequent calls return `nil`.
  public mutating func next() -> Element? {
    if _position == _end { return nil }

    let result = _position!.pointee
    _position! += 1
    return result
  }

  internal var _position, _end: UnsafePointer<Element>?
}

%for Mutable in ('Mutable', ''):
/// A non-owning pointer to a buffer of ${Mutable.lower()} elements stored
/// contiguously in memory, presenting a collection interface to the
/// underlying elements.
///
/// The pointer should be aligned to `MemoryLayout<Element>.alignment`.

// FIXME: rdar://18157434 - until this is fixed, this has to be fixed layout
// to avoid a hang in Foundation, which has the following setup:
// struct A { struct B { let x: UnsafeMutableBufferPointer<...> } let b: B }
@_fixed_layout
public struct Unsafe${Mutable}BufferPointer<Element>
  : _${Mutable}Indexable, ${Mutable}Collection, RandomAccessCollection {

  public typealias Index = Int
  public typealias IndexDistance = Int
  public typealias Iterator =
    IndexingIterator<Unsafe${Mutable}BufferPointer<Element>>

  /// Always zero, which is the index of the first element in a
  /// non-empty buffer.
  public var startIndex: Int {
    return 0
  }

  /// The "past the end" position---that is, the position one greater than the
  /// last valid subscript argument.
  ///
  /// The `endIndex` property of an `Unsafe${Mutable}BufferPointer` instance is
  /// always identical to `count`.
  public var endIndex: Int {
    return count
  }

  public func index(after i: Int) -> Int {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    return i + 1
  }

  public func formIndex(after i: inout Int) {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    i += 1
  }

  public func index(before i: Int) -> Int {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    return i - 1
  }

  public func formIndex(before i: inout Int) {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    i -= 1
  }

  public func index(_ i: Int, offsetBy n: Int) -> Int {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    return i + n
  }

  public func index(
    _ i: Int, offsetBy n: Int, limitedBy limit: Int
  ) -> Int? {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    let l = limit - i
    if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
      return nil
    }
    return i + n
  }

  public func distance(from start: Int, to end: Int) -> Int {
    // NOTE: this is a manual specialization of index movement for a Strideable
    // index that is required for UnsafeBufferPointer performance. The
    // optimizer is not capable of creating partial specializations yet.
    // NOTE: Range checks are not performed here, because it is done later by
    // the subscript function.
    return end - start
  }

  public func _failEarlyRangeCheck(_ index: Int, bounds: Range<Int>) {
    // NOTE: This method is a no-op for performance reasons.
  }

  public func _failEarlyRangeCheck(_ range: Range<Int>, bounds: Range<Int>) {
    // NOTE: This method is a no-op for performance reasons.
  }

  public typealias Indices = CountableRange<Int>

  public var indices: Indices {
    return startIndex..<endIndex
  }

  /// Accesses the `i`th element in the buffer.
  public subscript(i: Int) -> Element {
    get {
      _debugPrecondition(i >= 0)
      _debugPrecondition(i < endIndex)
      return _position![i]
    }
%if Mutable:
    nonmutating set {
      _debugPrecondition(i >= 0)
      _debugPrecondition(i < endIndex)
      _position![i] = newValue
    }
%end
  }

  public subscript(bounds: Range<Int>)
    -> ${Mutable}RandomAccessSlice<Unsafe${Mutable}BufferPointer<Element>>
  {
    get {
      _debugPrecondition(bounds.lowerBound >= startIndex)
      _debugPrecondition(bounds.upperBound <= endIndex)
      return ${Mutable}RandomAccessSlice(
        base: self, bounds: bounds)
    }
%  if Mutable:
    set {
      _debugPrecondition(bounds.lowerBound >= startIndex)
      _debugPrecondition(bounds.upperBound <= endIndex)
      // FIXME: swift-3-indexing-model: tests.
      _writeBackMutableSlice(&self, bounds: bounds, slice: newValue)
    }
%  end
  }

  /// Creates an Unsafe${Mutable}Pointer over the `count` contiguous
  /// `Element` instances beginning at `start`.
  ///
  /// If `start` is nil, `count` must be 0. However, `count` may be 0 even for
  /// a nonzero `start`.
  public init(start: Unsafe${Mutable}Pointer<Element>?, count: Int) {
    _precondition(
      count >= 0, "Unsafe${Mutable}BufferPointer with negative count")
    _precondition(
      count == 0 || start != nil,
      "Unsafe${Mutable}BufferPointer has a nil start and nonzero count")
    _position = start
    _end = start.map { $0 + count }
  }

  /// Returns an iterator over the elements of this sequence.
  ///
  /// - Complexity: O(1).
  public func makeIterator() -> UnsafeBufferPointerIterator<Element> {
    return UnsafeBufferPointerIterator(_position: _position, _end: _end)
  }

  /// A pointer to the first element of the buffer.
  public var baseAddress: Unsafe${Mutable}Pointer<Element>? {
    return _position
  }

  /// The number of elements in the buffer.
  public var count: Int {
    if let pos = _position {
      return _end! - pos
    }
    return 0
  }

  let _position, _end: Unsafe${Mutable}Pointer<Element>?
}

extension Unsafe${Mutable}BufferPointer : CustomDebugStringConvertible {
  /// A textual representation of `self`, suitable for debugging.
  public var debugDescription: String {
    return "Unsafe${Mutable}BufferPointer"
      + "(start: \(_position.map(String.init(describing:)) ?? "nil"), count: \(count))"
  }
}
%end

@available(*, unavailable, renamed: "UnsafeBufferPointerIterator")
public struct UnsafeBufferPointerGenerator<Element> {}

// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:
